package com.hontech.bvapp2.device.cp

import com.hontech.bvapp2.device.Address
import com.hontech.bvapp2.device.DeviceConn
import com.hontech.bvapp2.device.Frame
import com.hontech.bvapp2.utils.hex16
import com.hontech.bvapp2.utils.isBitSet
import com.hontech.bvapp2.utils.postEvent
import serial.codec.ByteView
import serial.codec.Uint16
import serial.codec.u32
import serial.codec.u8

private const val PICK_CTRL = 0x04
private const val CY_CTRL = 0x05
private const val CARGO_CTRL = 0x06
private const val SCAN = 0x07
private const val SCAN_LED = 0x08
private const val ROW_COL_CTRL = 0x09

object Cargo {

    suspend fun scanLed(cargoId: Int, ctrl: Int) {
        DeviceConn.simpleReq(
            address(cargoId),
            SCAN_LED,
            ctrl.u8()
        ).parse()
    }

    suspend fun rowColCtrl(cargoId: Int, rowPosition: Int, colPosition: Int) {
        DeviceConn.req(
            address(cargoId),
            ROW_COL_CTRL,
            rowPosition.u32(),
            colPosition.u32()
        ).parse()
    }

    suspend fun scan(cargoId: Int): String {
        val bw = ByteView()
        DeviceConn.req(
            address(cargoId),
            SCAN
        ).parse(bw)
        return bw.toString()
    }

    suspend fun cargoCtrl(cargoId: Int, position: Int) {
        DeviceConn.req(
            address(cargoId),
            CARGO_CTRL,
            position.u32()
        ).parse()
    }

    suspend fun cyCtrl(cargoId: Int, ctrl: Int) {
        DeviceConn.req(
            address(cargoId),
            CY_CTRL,
            ctrl.u8()
        ).parse()
    }

    suspend fun pickCtrl(cargoId: Int, position: Int) {
        DeviceConn.req(
            address(cargoId),
            PICK_CTRL,
            position.u32()
        ).parse()
    }

    private fun address(cargoId: Int): Int {
        return if (cargoId == 1) {
            Address.CARGO1
        } else {
            Address.CARGO2
        }
    }

    fun cargoPositionWithCol(col: Int, offset: Int = 0): Int {
        return ((col - 1) * 483) + offset
    }

    private const val CIRCLE_PULS_COUNT = (2870.2 * 40.0 / 26.0 * 10.0 * 400.0 / 762.0).toInt()

    // 链条长度: 2870.2mm
// 同步轮 40, 26
// 减速器 10
// 大齿轮周长 762mm
// 行间距 114.3,  第二行: 114.3 + 12.7
    private fun cargoPositionWithMm(mm: Double): Int {
        val value = 40.0 / 26.0 * 10.0 * 400.0 / 762.0 * mm
        return value.toInt()
    }

    private fun cargoPositionWithRow(row: Int, other: Double = 0.0): Int {
        // let mm = 6.35;
        // if (row == 1) {
        //     row = 0
        // } else if (row == 2) {
        //     mm = 114.3 + 6.35;
        // } else if (row <= 25) {
        //     mm = 114.3 * (row - 1) + 6.35;
        // } else {
        //     throw 'invalid row';
        // }
        return cargoPositionWithMm(114.3 * (row - 1) + other)
    }

    // 400 4
    fun cargoScanPositionWithRow(row: Int, offset: Int = 450): Int {
        // 3 25
        // 2 24
        // 1 23
        var n = row - 3
        var other = 0.0
        if (row <= 3) {
            other = 12.7
            n = row + 22
        }
        val count = cargoPositionWithRow(n, other) + offset
        val count2 = count % CIRCLE_PULS_COUNT
        if (count2 > 0) {
            return count2
        }
        return count2 + CIRCLE_PULS_COUNT
    }

    fun cargoPickPositionWithRow(row: Int, offset: Int = 380 - 50): Int {
        var n = row - 4
        var other = 0.0
        if (row <= 4) {
            n = row + 21
            other = 12.7
        }

        val count = cargoPositionWithRow(n, other) + offset
        val count2 = count % CIRCLE_PULS_COUNT
        if (count2 > 0) {
            return count2
        }
        return count2 + CIRCLE_PULS_COUNT
    }

    fun onStatus(frame: Frame) {
        val src = frame.src
        if (src == Address.CARGO1) {
            status1 = parseStatus(1, frame)
        } else if (src == Address.CARGO2) {
            status2 = parseStatus(2, frame)
        }
    }

    private fun parseStatus(cargoId: Int, frame: Frame): Status {
        val version = Uint16()
        val sensor = Uint16()
        frame.parse(version, sensor)
        val status = Status(cargoId, version.value, sensor.value)
        postEvent(status)
        return status
    }

    var status1: Status? = null
        private set

    var status2: Status? = null

    class Status(
        val cargoId: Int,
        val version: Int,
        val sensor: Int,
    ) {

        fun version() = version.hex16()

        fun isCyInner() = sensor.isBitSet(0)
        fun isCyExtern() = sensor.isBitSet(1)
        fun isCyTop() = sensor.isBitSet(2)
        fun isCyBottom() = sensor.isBitSet(3)
        fun isPickOrigin() = sensor.isBitSet(4)
        fun isCompChecked() = sensor.isBitSet(5)
        fun isCargoBtn() = sensor.isBitSet(6)
        fun isCargoOrigin() = sensor.isBitSet(7)
        fun isSen2() = sensor.isBitSet(8)
        fun isPickAlm() = sensor.isBitSet(9)
        fun isCargoAlm() = sensor.isBitSet(10)
    }
}

